package forces;

import java.util.Collection;
import java.util.Scanner;
import simulation.Mass;
import util.Location;
import util.Vector;


/**
 * This class represents a force that attracts masses in an assembly towards
 * their center
 * 
 */
public class CenterOfMassForce extends Force {
    private static final double DEFAULT_MAGNITUDE = 200;
    private static final double DEFAULT_EXPONENT = 0;
    private double myMagnitude;
    private double myExponent;

    /**
     * A default constructor that picks default values for how the force should
     * be calculated
     */
    public CenterOfMassForce () {
        this(DEFAULT_MAGNITUDE, DEFAULT_EXPONENT);
    }

    /**
     * Creates a COM force with the specified magnitude and exponent. Also
     * passed a model which contains a collection of all the masses present.
     * 
     */
    public CenterOfMassForce (double magnitude, double exponent) {
        super();
        myMagnitude = magnitude;
        myExponent = exponent;
    }

    public CenterOfMassForce (Scanner line) {
        this(line.nextDouble(), line.nextDouble());
    }

    /**
     * Implements the abstract update method to calculate and apply
     * the center of mass force on each mass.
     */
    @Override
    public void update (Collection<Mass> masses) {
        Location comLoc = calculateCOM(masses);
        for (Mass m : masses) {
            Location massLoc = new Location(m.getX(), m.getY());
            Vector v = massLoc.difference(comLoc);
            setMagnitude(myMagnitude / Math.pow(v.getMagnitude(), myExponent));
            setDirection(v.getDirection());
            m.applyForce(this);
        }
    }

    /**
     * Finds the center of mass for a collection of masses.
     */
    private Location calculateCOM (Collection<Mass> masses) {
        double x = 0;
        double y = 0;
        double totalMass = 0;

        for (Mass m : masses) {
            x += m.getX() * m.getMass();
            y += m.getY() * m.getMass();
            totalMass += m.getMass();
        }
        return new Location(x / totalMass, y / totalMass);
    }
}
